format ELF64 executable 3
entry Start
;-------------------------------------------------------------------------------
; NAME:     length2
; IN:       xmm0.xy     two component vector
; OUT:      xmm0.xyzw   length of the input vector
;-------------------------------------------------------------------------------
macro       length2     {
            mulps       xmm0,xmm0
            movaps      xmm1,xmm0
            shufps      xmm0,xmm0,0x00
            shufps      xmm1,xmm1,0x55
            addps       xmm0,xmm1
            sqrtps      xmm0,xmm0
}
;-------------------------------------------------------------------------------
segment readable executable
;-------------------------------------------------------------------------------
; NAME:     sin
; IN:       xmm0.xyzw   x,y,z,w
; OUT:      xmm0.xyzw   sin(x),sin(y),sin(z),sin(w)
;-------------------------------------------------------------------------------
align 16
sin:
            movaps      xmm7,xmm0
            andps       xmm0,dqword [g_inv_sign_mask]
            andps       xmm7,dqword [g_sign_mask]
            mulps       xmm0,dqword [g_2_div_pi]
            pxor        xmm3,xmm3
            movdqa      xmm5,dqword [g_1]
            movaps      xmm4,dqword [g_1_0]
            cvttps2dq   xmm2,xmm0
            pand        xmm5,xmm2
            pcmpeqd	    xmm5,xmm3
            cvtdq2ps    xmm6,xmm2
            pand        xmm2,dqword [g_2]
            pslld       xmm2,30
            subps       xmm0,xmm6
            minps       xmm0,xmm4
            subps       xmm4,xmm0
            andps       xmm0,xmm5
            andnps      xmm5,xmm4
            orps        xmm0,xmm5
            movaps      xmm1,xmm0
            mulps       xmm0,xmm0
            xorps       xmm2,xmm7
            orps        xmm1,xmm2
            movaps      xmm7,xmm0
            mulps       xmm0,dqword [g_sincos_p3]
            addps       xmm0,dqword [g_sincos_p2]
            mulps       xmm0,xmm7
            addps       xmm0,dqword [g_sincos_p1]
            mulps       xmm0,xmm7
            addps       xmm0,dqword [g_sincos_p0]
            mulps       xmm0,xmm1
            ret
;-------------------------------------------------------------------------------
; NAME:     cos
; IN:       xmm0.xyzw   x,y,z,w
; OUT:      xmm0.xyzw   cos(x),cos(y),cos(z),cos(w)
;-------------------------------------------------------------------------------
align 16
cos:
            andps       xmm0,dqword [g_inv_sign_mask]
            addps       xmm0,dqword [g_0_5pi]
            mulps       xmm0,dqword [g_2_div_pi]
            pxor        xmm3,xmm3
            movdqa      xmm5,dqword [g_1]
            movaps      xmm4,dqword [g_1_0]
            cvttps2dq   xmm2,xmm0
            pand        xmm5,xmm2
            pcmpeqd	    xmm5,xmm3
            cvtdq2ps    xmm6,xmm2
            pand        xmm2,dqword [g_2]
            pslld       xmm2,30
            subps       xmm0,xmm6
            minps       xmm0,xmm4
            subps       xmm4,xmm0
            andps       xmm0,xmm5
            andnps      xmm5,xmm4
            orps        xmm0,xmm5
            movaps      xmm1,xmm0
            mulps       xmm0,xmm0
            orps        xmm1,xmm2
            movaps      xmm7,xmm0
            mulps       xmm0,dqword [g_sincos_p3]
            addps       xmm0,dqword [g_sincos_p2]
            mulps       xmm0,xmm7
            addps       xmm0,dqword [g_sincos_p1]
            mulps       xmm0,xmm7
            addps       xmm0,dqword [g_sincos_p0]
            mulps       xmm0,xmm1
            ret
;-------------------------------------------------------------------------------
; NAME:     atanr2
; IN:       xmm0.xyzw   x0,x1,x2,x3
; IN:       xmm1.xyzw   y0,y1,y2,y3
; OUT:      xmm0.xyzw   atan2(x0,1/y0),atan2(x1,1/y1),atan2(x2,1/y2),atan2(x3,1/y3)
;-------------------------------------------------------------------------------
align 16
atanr2:
            movaps      xmm2,dqword [g_sign_mask]
            xorps       xmm3,xmm3
            movaps      xmm5,dqword [g_1_0]
            andps       xmm2,xmm0
            mulps       xmm0,xmm1
            orps        xmm2,dqword [g_pi]
            cmpleps	    xmm3,xmm1
            movaps      xmm6,dqword [g_m1_0]
            rcpps       xmm4,xmm0
            cmpltps	    xmm5,xmm0
            cmpnleps    xmm6,xmm0
            movaps      xmm1,dqword [g_atan_s0]
            orps        xmm5,xmm6
            movaps      xmm8,xmm2
            movaps      xmm9,xmm3
            andps       xmm4,xmm5
            movaps      xmm2,dqword [g_atan_t0]
            movaps      xmm7,xmm5
            andnps      xmm5,xmm0
            movaps      xmm3,dqword [g_atan_s1]
            orps        xmm4,xmm5
            movaps      xmm0,xmm4
            movaps      xmm6,dqword [g_atan_t1]
            mulps       xmm4,xmm4
            addps       xmm1,xmm4
            movaps      xmm5,dqword [g_atan_s2]
            rcpps       xmm1,xmm1
            mulps       xmm1,xmm2
            movaps      xmm2,dqword [g_atan_t2]
            addps       xmm3,xmm4
            addps       xmm1,xmm3
            movaps      xmm3,dqword [g_atan_s3]
            rcpps       xmm1,xmm1
            mulps       xmm1,xmm6
            movaps      xmm6,dqword [g_atan_t3]
            addps       xmm5,xmm4
            addps       xmm1,xmm5
            movaps      xmm5,dqword [g_sign_mask]
            rcpps       xmm1,xmm1
            mulps       xmm1,xmm2
            addps       xmm3,xmm4
            movaps      xmm4,dqword [g_0_5pi]
            mulps       xmm6,xmm0
            addps       xmm1,xmm3
            andps       xmm0,xmm5
            rcpps       xmm1,xmm1
            movaps      xmm3,xmm9
            mulps       xmm1,xmm6
            orps        xmm0,xmm4
            subps       xmm0,xmm1
            movaps      xmm2,xmm8
            andps       xmm0,xmm7
            andnps      xmm7,xmm1
            orps        xmm0,xmm7
            movaps      xmm1,xmm0
            andps       xmm0,xmm3
            addps       xmm1,xmm2
            andnps      xmm3,xmm1
            orps        xmm0,xmm3
            ret
;-------------------------------------------------------------------------------
; NAME:     ComputeColor
; IN:       xmm0.xyzw   normalized x coordinate (replicated)
; IN:       xmm1.xyzw   normalized y coordinate (replicated)
; OUT:      xmm0.xyz    pixel color
;-------------------------------------------------------------------------------
align 16
ComputeColor:
x                       equ rbp-16
y                       equ rbp-32
xy                      equ rbp-48
a                       equ rbp-64
r                       equ rbp-80
s                       equ rbp-96
t                       equ rbp-112
            push        rbp
            mov         rbp,rsp
            sub         rsp,256
            movaps      [x],xmm0
            movaps      [y],xmm1
            movss       [xy+0],xmm0
            movss       [xy+4],xmm1
            ; a = atanr2(y,1/x) = atan(y,x)
            movaps      xmm2,xmm0
            movaps      xmm0,xmm1
            rcpps       xmm1,xmm2
            call        atanr2
            movaps      [a],xmm0
            ; r = length2(xy)
            movaps      xmm0,[xy]
            length2
            movaps      [r],xmm0
            ; s = 0.5 + 0.5*sin(3.0*a)
            movaps      xmm0,[a]
            mulps       xmm0,dqword [g_c0]
            call        sin
            mulps       xmm0,dqword [g_0_5]
            addps       xmm0,dqword [g_0_5]
            movaps      [s],xmm0
            ; t = 0.2 + 0.4*pow(s,0.25)
            movaps      xmm0,[s]
            sqrtps      xmm0,xmm0
            sqrtps      xmm0,xmm0
            mulps       xmm0,dqword [g_c1]
            addps       xmm0,dqword [g_c2]
            movaps      [t],xmm0
            ; t += 0.04*cos(6.0*a)
            movaps      xmm0,[a]
            mulps       xmm0,dqword [g_c3]
            call        cos
            mulps       xmm0,dqword [g_c4]
            addps       xmm0,[t]
            movaps      [t],xmm0
            ; if (r < t)
            movaps      xmm0,[r]
            cmpltps     xmm0,[t]
            movaps      xmm1,dqword [g_green]
            andps       xmm1,xmm0
            movaps      xmm2,dqword [g_white]
            andnps      xmm0,xmm2
            orps        xmm0,xmm1
            mov         rsp,rbp
            pop         rbp
            ret
restore                 x,y,xy,a,r,s,t
;-------------------------------------------------------------------------------
; NAME:     Start
; DESC:     Program entry point.
;-------------------------------------------------------------------------------
Start:
imgptr                  equ rbp-8
x                       equ rbp-12
y                       equ rbp-16
            mov         rbp,rsp
            sub         rsp,32
            ; alloc memory
            mov         eax,9               ; sys_mmap
            xor         edi,edi             ; addr
            mov         esi,IMG_W*IMG_H*4   ; length
            mov         edx,0x1+0x2         ; PROT_READ | PROT_WRITE
            mov         r10d,0x02+0x20      ; MAP_PRIVATE | MAP_ANONYMOUS
            mov         r8,-1               ; fd
            xor         r9d,r9d             ; offset
            syscall
            mov         [imgptr],rax
            mov         rbx,rax
            ; begin loops
            mov         dword [y],0
.LoopY:
            mov         dword [x],0
.LoopX:
            ; compute normalized x coordinate [-1.0 , 1.0]
            cvtsi2ss    xmm0,[x]
            divss       xmm0,[g_img_w]
            shufps      xmm0,xmm0,0x00
            subps       xmm0,dqword [g_0_5]
            addps       xmm0,xmm0
            ; compute normalized y coordinate [-1.0 , 1.0]
            cvtsi2ss    xmm1,[y]
            divss       xmm1,[g_img_h]
            shufps      xmm1,xmm1,0x00
            subps       xmm1,dqword [g_0_5]
            addps       xmm1,xmm1
            call        ComputeColor
            ; clamp to [0.0 , 1.0]
            maxps       xmm0,dqword [g_0_0]
            minps       xmm0,dqword [g_1_0]
            ; convert from [0.0 , 1.0] to [0 , 255]
            mulps       xmm0,dqword [g_255_0]
            cvttps2dq   xmm0,xmm0
            pshufb      xmm0,dqword [g_img_conv_mask]
            ; set alpha to 0xff
            movd        eax,xmm0
            or          eax,0xff000000
            mov         [rbx],eax
            ; advance pixel pointer
            add         rbx,4
            ; continue .LoopX
            inc         dword [x]
            cmp         dword [x],IMG_W
            jne         .LoopX
            ; continue .LoopY
            inc         dword [y]
            cmp         dword [y],IMG_H
            jne         .LoopY
            ; create TGA file
            mov         eax,85
            mov         rdi,g_tga_name
            mov         esi,110000000b
            syscall
            mov         rbx,rax
            ; write header
            mov         eax,1
            mov         rdi,rbx
            mov         rsi,g_tga_head
            mov         edx,18
            syscall
            ; write pixel data
            mov         eax,1
            mov         rdi,rbx
            mov         rsi,[imgptr]
            mov         edx,IMG_W*IMG_H*4
            syscall
            ; terminate process
            mov         eax,60
            xor         edi,edi
            syscall
restore                 imgptr,x,y
;-------------------------------------------------------------------------------
segment readable
;-------------------------------------------------------------------------------
align 1
g_tga_name              db 'clover.tga',0
g_tga_head              db 0,0,2,9 dup 0,(IMG_W and 0x00ff),(IMG_W and 0xff00) shr 8,(IMG_H and 0x00ff),(IMG_H and 0xff00) shr 8,32,0

align 4
g_img_w                 dd 800.0
g_img_h                 dd 800.0
IMG_W=800
IMG_H=800

align 16
g_c0                    dd 4 dup 3.0
g_c1                    dd 4 dup 0.4
g_c2                    dd 4 dup 0.2
g_c3                    dd 4 dup 6.0
g_c4                    dd 4 dup 0.05
g_white                 dd 4 dup 1.0
g_green                 dd 0.0,1.0,0.0,1.0

g_img_conv_mask         db 8,4,0,12,12 dup 0x80
g_0_0                   dd 4 dup 0.0
g_0_5                   dd 4 dup 0.5
g_1_0                   dd 4 dup 1.0
g_m1_0                  dd 4 dup -1.0
g_255_0                 dd 4 dup 255.0
g_1                     dd 4 dup 1
g_2                     dd 4 dup 2
g_sign_mask             dd 4 dup 0x80000000
g_inv_sign_mask         dd 4 dup not 0x80000000
g_0_5pi                 dd 4 dup 1.57079633
g_2_div_pi              dd 4 dup 0.636619772
g_pi                    dd 4 dup 3.1415926535897

g_sincos_p0             dd 4 dup 1.5707963267948963959
g_sincos_p1             dd 4 dup -0.64596409750621907082
g_sincos_p2             dd 4 dup 0.07969262624561800806
g_sincos_p3             dd 4 dup -0.00468175413106023168

g_atan_t0               dd 4 dup -0.091646118527267623468
g_atan_t1               dd 4 dup -1.3956945682312098640
g_atan_t2               dd 4 dup -94.393926122725531747
g_atan_t3               dd 4 dup 12.888383034157279340
g_atan_s0               dd 4 dup 1.2797564625607904396
g_atan_s1               dd 4 dup 2.1972168858277355914
g_atan_s2               dd 4 dup 6.8193064729268275701
g_atan_s3               dd 4 dup 28.205206687035841409
;-------------------------------------------------------------------------------
